package com.easylinkin.linkappapi.hcmy.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.hcmy.mapper.CarLocusMapper;
import com.easylinkin.linkappapi.hcmy.service.CarLocusService;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.elasticsearch.service.IEService;
import com.easylinkin.linkappapi.positioning.entity.*;
import com.easylinkin.linkappapi.positioning.service.MonitorMapService;
import com.easylinkin.linkappapi.positioning.service.TrackPlaybackService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.tophits.TopHits;
import org.elasticsearch.search.aggregations.metrics.tophits.TopHitsAggregationBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * class info :
 *
 * @author liuqihang
 * @date 2021/9/22 12:14
 */
@Service
@Slf4j
public class CarLocusServiceImpl extends ServiceImpl<CarLocusMapper, Device> implements CarLocusService {

    @Resource
    private LinkappUserContextProducer linkappUserContextProducer;

    @Resource
    private TrackPlaybackService trackPlaybackService;

    @Resource
    private IEService ieService;

    @Resource
    private MonitorMapService monitorMapService;

    @Override
    public MonitorMapStatistics getStatisticsInfo(QueryMonitorMap queryMonitorMap) {
        try {
            String tenantId = linkappUserContextProducer.getNotNullCurrent().getTenantId();
            queryMonitorMap.setTenantId(tenantId);
            MonitorMapStatistics statisticsInfo = baseMapper.getStatisticsInfo(queryMonitorMap);
            return statisticsInfo;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public List<MonitorMapDevice> getDeviceList(QueryMonitorMap queryMonitorMap) {
        try {
            String tenantId = linkappUserContextProducer.getNotNullCurrent().getTenantId();
            queryMonitorMap.setTenantId(tenantId);

            List<Device> deviceList = baseMapper.getDeviceList(queryMonitorMap);
            if(deviceList == null || deviceList.isEmpty()){
                return null;
            }

            //从流水获取车辆最后定位坐标
            List<String> codeList = deviceList.stream().map(Device::getCode).collect(Collectors.toList());
            Map<String, Object> likeQueryMap = new HashMap<>(16);
            likeQueryMap.put("deviceCode", codeList);
            int size = (codeList == null || codeList.size() <= 0) ? 1 : codeList.size();
            List<CarDeviceEs> carDeviceEsList = queryEsData(likeQueryMap, 1, size);
            try {
                trackPlaybackService.reqConvert(carDeviceEsList);
            } catch (Exception e) {
                e.printStackTrace();
            }

            Map<String, List<CarDeviceEs>> collect = carDeviceEsList.stream().collect(Collectors.groupingBy(CarDeviceEs::getDeviceCode));

            //调用高德API获取详细地址,这里逻辑调整为单个设备经纬度去请求，批量去请求的话，只要有一个经纬度坐标数据有问题，会影响到其他设备的逆地理编码查询
            Map<String, String> positionAddressMap = new LinkedHashMap<>();
            if(carDeviceEsList != null && !carDeviceEsList.isEmpty()){
                for (CarDeviceEs carDeviceEs:
                        carDeviceEsList) {
                    Map<String, String> resultMap = getPositionAddress(carDeviceEs);
                    if(resultMap != null && resultMap.size() > 0){
                        positionAddressMap.putAll(resultMap);
                    }
                }
            }

            //封装数据
            List<MonitorMapDevice> monitorMapDeviceList = new ArrayList<MonitorMapDevice>();
            for (Device device:
                    deviceList) {
                MonitorMapDevice monitorMapDevice = new MonitorMapDevice();
                monitorMapDevice.setAreaId(device.getAreaId())
                        .setAreaPath(device.getAreaPath())
                        .setCode(device.getCode())
                        .setName(device.getName())
                        .setStatus(device.getStatus())
                        .setCarCode(device.getCarCode())
                        .setOnlineState(device.getOnlineState());
                List<CarDeviceEs> childCarDeviceEsList = collect.get(device.getCode());
                if(childCarDeviceEsList != null && childCarDeviceEsList.size() > 0){
                    CarDeviceEs carDeviceEs = childCarDeviceEsList.get(0);
                    CarDeviceEsData data = carDeviceEs.getData();
                    if(data != null){
                        String positionAddress = "无法获取";
                        if(positionAddressMap != null && positionAddressMap.size() > 0){
                            positionAddress = positionAddressMap.get(carDeviceEs.getLongitudeAndLatitude());
                        }
                        monitorMapDevice.setSpeed(data.getSpeed())
                                .setPositionAddress(positionAddress)
                                .setLongitude(data.getLongitude())
                                .setLatitude(data.getLatitude())
                                .setLongitudeConvert(data.getLongitudeConvert())
                                .setLatitudeConvert(data.getLatitudeConvert())
                                .setDirection(data.getDirection())
                                .setIMEI(data.getIMEI())
                                .setPositioningTime(data.getPositioningTime());
                    }
                }
                if(monitorMapDevice.getPositionAddress() == null){
                    monitorMapDevice.setPositionAddress("无法获取");
                }
                monitorMapDeviceList.add(monitorMapDevice);
            }
            return monitorMapDeviceList;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public Map<String, String> getPositionAddress(CarDeviceEs carDeviceEs) throws ExecutionException, InterruptedException {
        List<CarDeviceEs> carDeviceEsList = new ArrayList<>();
        carDeviceEsList.add(carDeviceEs);
        return monitorMapService.getPositionAddress(carDeviceEsList);
    }

    private List<CarDeviceEs> queryEsData(Map<String, Object> likeQueryMap, int index, int size){
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("groupDeviceCode").field("deviceCode");
        String[] includes_source = new String[]{"deviceCode", "data", "storageTime", "deviceName", "showMessage"};
        String[] excludes_source = new String[]{};

        TopHitsAggregationBuilder sort = AggregationBuilders.topHits("top_device_hits")
                .fetchSource(includes_source, excludes_source)
                .size(1)
                .sort("storageTime", SortOrder.DESC);
        termsAggregationBuilder.subAggregation(sort);
        List<CarDeviceEs> carDeviceEsList = new ArrayList<CarDeviceEs>();

        /**SortField sortField = new SortField().setFieldName("data.positioning_time.keyword").setSortOrder(SortOrder.DESC);**/

        List<String> necessaryFieldList = new ArrayList<>();
        necessaryFieldList.add("positioning_time");

        SearchResponse searchResponse = ieService.getDeviceFlowListFromES(likeQueryMap, index, size, null, necessaryFieldList,
                null, termsAggregationBuilder);
        if (Objects.nonNull(searchResponse) && Objects.equals(searchResponse.status(), RestStatus.OK)) {
            Terms deviceCodeGroupResult = searchResponse.getAggregations().get("groupDeviceCode");
            if (Objects.nonNull(deviceCodeGroupResult)) {
                for (Terms.Bucket groupBucket2 : deviceCodeGroupResult.getBuckets()) {
                    TopHits topScoreResult = groupBucket2.getAggregations().get("top_device_hits");
                    if (Objects.nonNull(topScoreResult) && topScoreResult.getHits().getHits().length > 0) {
                        SearchHit searchHit = topScoreResult.getHits().getAt(0);
                        CarDeviceEs dr = JSON.parseObject(searchHit.getSourceAsString(), CarDeviceEs.class);
                        carDeviceEsList.add(dr);
                    }
                }
            }
        }
        return carDeviceEsList;
    }
}
